home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1994 November / macformat-018.iso / Utility Spectacular / Developer / hex Folder / Hex.p < prev    next >
Encoding:
Text File  |  1992-09-30  |  16.7 KB  |  590 lines  |  [TEXT/MPS ]

  1.  {=============================================================================
  2.  
  3.  FILE Hex.p
  4.  
  5.  NAME
  6.     Hex -- reads a resource from a file and converts it to raw/Intel/Motorola hex format.
  7.  
  8.  SYNOPSIS
  9.     Hex file [-p] [-a address] [-h hextype] [-m hexmode] [-r rType] [-i rID] [-s skip]
  10.  
  11.  DESCRIPTION
  12.     Hex converts a resource to an ASCII HEX file.
  13.  
  14.  OPTIONS
  15.     -p     Writes progress information to diagnostic output (default: no progress info)
  16.     -a     Specify start address of output file (default: 0)
  17.     -h     Hex type: raw|intel|s1|s2|s3 (default: intel)
  18.     -m     Hex mode: all|even|odd (default: all)
  19.     -r     Resource type (default: CODE)
  20.     -i     Resource ID (default: 1)
  21.     -s     No of bytes to skip at start of resource (default: 4)
  22.  
  23.     Note:  Numeric options may be specified in decimal (nnn) or hex ($nnn)
  24.  
  25.  DIAGNOSTICS
  26.     0 Normal termination.
  27.     1 Syntax error.
  28.     2 Resource file not found.
  29.     3 Resource not found.
  30.     4 Execution aborted.
  31.  
  32.  MODIFICATION HISTORY
  33.      4/10/87 Added odd/even byte splitting
  34.                      Added start address dialog
  35.                      Added code size to conversion dialog
  36.                      Improved format of conversion dialog
  37.     12/10/87 Opens files of type 'CODE' or 'DATA' in addition to 'APPL'
  38.     28/01/88 Converted to MPW 2.0.2, Pascal 2.0.2
  39.     23/10/88 Converted to MPW Tool
  40.     15/12/88 Upgraded to MPW 3.0b1
  41.         6/5/90 Upgraded to MPW 3.1
  42.      30/9/92 Upgraded to MPW 3.3
  43.                      Tidied up for release
  44.  
  45.  KNOWN BUGS
  46.     Can only handle CODE resources up to 32k bytes
  47.     Doesn't check for APPL's which might already be open (eg. under MultiFinder)
  48.     Motorola S3 (32 bit addresses) probably don't work for addresses > $7FFFFFFF (we use a LongInt for address)
  49.  
  50.  Copyright Paul Russell, ARC Electronics, 1987-1992.
  51.  
  52.  =============================================================================}
  53.  
  54. PROGRAM Hex;
  55.  
  56.     USES Memtypes, Quickdraw, OSIntf, ToolIntf, PackIntf, { Mac interface }
  57.              CursorCtl, { spinning cursor }
  58.              Signal, { command-period handling }
  59.              PasLibIntf, { standard I/O etc }
  60.              IntEnv; { argV and argC }
  61.  
  62.     CONST
  63.         Version = '1.021'; { MPW version resource (used by SetVersion Tool) }
  64.         kNull = ''; { null string }
  65.         kSpace = ' '; { space character }
  66.         kMaxCodeSize = MAXINT; { the biggest code resource we can handle }
  67.  
  68.     TYPE
  69.         Str1 = STRING[1];
  70.  
  71.         Code = PACKED ARRAY [0..kMaxCodeSize] OF Byte;
  72.         CodePtr = ^Code;
  73.         CodeHandle = ^CodePtr;
  74.  
  75.         HexTypes = (raw, intel, motorolaS1, motorolaS2, motorolaS3);
  76.         HexModes = (allBytes, evenBytes, oddBytes);
  77.  
  78.         RetCodes = (RC_Normal, RC_ParmErrs, RC_FileNotFound, RC_ResNotFound, RC_Abort); { return codes }
  79.  
  80.         Nybble = 0..15;
  81.  
  82.     VAR
  83.         codeH: CodeHandle; { handle to our CODE resource }
  84.         progress: Boolean; { progress info on diagnostic file }
  85.         address: LongInt; { start address }
  86.         hexType: HexTypes; { hex type, raw/intel/s1/s2/s3 }
  87.         hexMode: HexModes; { hex mode, all/even/odd bytes }
  88.         rType: ResType; { resource type }
  89.         rID: INTEGER; { resource ID }
  90.         skip: INTEGER; { no of bytes to skip at start of resource }
  91.         fileRef: INTEGER; { the refnum for our file }
  92.         fileName: Str255; { the name of the file we're HEX'ing }
  93.         progName: Str255; { program file name }
  94.         interrupted: Boolean; { interrupted (Command-. pressed) }
  95.         retCode: RetCodes; { return codes }
  96.  
  97.         {=== ToUpper - convert string to upper case ===}
  98.  
  99.     FUNCTION ToUpper(st: Str255): Str255;
  100.  
  101.         VAR
  102.             i: INTEGER;
  103.             ch: Char;
  104.  
  105.         BEGIN
  106.             FOR i := 1 TO Length(st) DO
  107.                 BEGIN
  108.                 ch := st[i];
  109.                 IF ch IN ['a'..'z'] THEN
  110.                     BEGIN
  111.                     ch := Chr(Ord(ch) - Ord('a') + Ord('A'));
  112.                     st[i] := ch;
  113.                     END;
  114.                 END;
  115.             ToUpper := st; { return upper case string }
  116.         END; { ToUpper }
  117.  
  118.     {=== HexChar - convert a nybble to a hexadecimal character ===}
  119.  
  120.     FUNCTION HexChar(i: Nybble): Char;
  121.  
  122.         CONST
  123.             hexChars = '0123456789ABCDEF';
  124.  
  125.         BEGIN { HexChar }
  126.             HexChar := hexChars[i + 1];
  127.         END; { HexChar }
  128.  
  129.     {=== NumToHexString - hex version of NumToString - only works for 0 <= i <= MAXLONGINT ===}
  130.  
  131.     PROCEDURE NumToHexString(num: LongInt;
  132.                                                      VAR st: Str255);
  133.  
  134.         VAR
  135.             digit: INTEGER;
  136.             st1: Str1;
  137.  
  138.         BEGIN { NumToHexString }
  139.             IF num <= 0 THEN
  140.                 st := '0'
  141.             ELSE
  142.                 BEGIN
  143.                 st := kNull;
  144.                 st1 := kSpace;
  145.                 WHILE num > 0 DO
  146.                     BEGIN
  147.                     st1[1] := HexChar(num MOD $10);
  148.                     st := concat(st1, st);
  149.                     num := num DIV $10;
  150.                     END;
  151.                 END;
  152.         END; { NumToHexString }
  153.  
  154.     {=== HexStringToNum - hex version of StringToNum ===}
  155.  
  156.     PROCEDURE HexStringToNum(st: Str255;
  157.                                                      VAR num: LongInt);
  158.  
  159.         VAR
  160.             i, digit: INTEGER;
  161.             digitFound: Boolean;
  162.             ch: Char;
  163.  
  164.         BEGIN { HexStringToNum }
  165.             num := 0;
  166.             digitFound := FALSE;
  167.             FOR i := 1 TO Length(st) DO { for each character in the string }
  168.                 BEGIN
  169.                 ch := st[i]; { get the character }
  170.                 IF ch IN ['0'..'9'] THEN { if decimal }
  171.                     BEGIN
  172.                     digit := Ord(ch) - Ord('0');
  173.                     digitFound := TRUE;
  174.                     END
  175.                 ELSE
  176.                     IF ch IN ['A'..'F'] THEN { if upper case hex letter }
  177.                         BEGIN
  178.                         digit := Ord(ch) - Ord('A') + 10;
  179.                         digitFound := TRUE;
  180.                         END
  181.                     ELSE
  182.                         IF ch IN ['a'..'f'] THEN { if lower case hex letter }
  183.                             BEGIN
  184.                             digit := Ord(ch) - Ord('a') + 10;
  185.                             digitFound := TRUE;
  186.                             END
  187.                         ELSE
  188.                             IF digitFound THEN { if we've just run out of valid chars }
  189.                                 Exit(HexStringToNum); { exit }
  190.                 IF digitFound THEN { if we have a valid char }
  191.                     num := num * $10 + digit; { shift number left one digit and add new digit }
  192.                 END;
  193.         END; { HexStringToNum }
  194.  
  195.     {=== Stop - terminate execution ===}
  196.  
  197.     PROCEDURE Stop(msg: Str255);
  198.  
  199.         BEGIN { Stop }
  200.             IF Length(msg) > 0 THEN
  201.                 BEGIN
  202.                 PLFlush(Output);
  203.                 WriteLn(Diagnostic);
  204.                 WriteLn(Diagnostic, msg);
  205.                 END;
  206.             IF interrupted THEN retCode := RC_Abort;
  207.             { don't worry about closing the files we opened - the Shell will do so if appropriate }
  208.             IF codeH <> NIL THEN { if we have allocated memory for our CODE resource }
  209.                 BEGIN
  210.                 HUnLock(Handle(codeH)); { unlock it }
  211.                 DisposHandle(Handle(codeH)); { dispose of it }
  212.                 END;
  213.             IEexit(Ord(retCode)); { exit, returning the appropriate status code }
  214.         END; { Stop }
  215.  
  216.     {=== Intr - Process external interrupt - this routine is passed to IEsigset ===}
  217.  
  218.     PROCEDURE Intr;
  219.  
  220.         BEGIN { Intr }
  221.             interrupted := TRUE; { we test this switch periodically }
  222.         END; { Intr }
  223.  
  224.     {$S Init }
  225.  
  226.     {=== SyntaxError - Report an error in parameters or options ===}
  227.  
  228.     PROCEDURE SyntaxError(message: Str255);
  229.  
  230.         BEGIN
  231.             PLFlush(Output);
  232.             WriteLn(Diagnostic, '### ', progName, ' - ', message);
  233.             Stop(concat('# Usage: ', progName, ' file [-p] [-a address] [-h hextype] [-m hexmode] [-r rType] [-i rID] [-s skip]'));
  234.         END;
  235.  
  236.     {=== GetNumArg - Get an INTEGER argument after a letter option ===}
  237.  
  238.     FUNCTION GetNumArg(VAR ArgVIndex: INTEGER;
  239.                                          Name: Str255;
  240.                                          Low, High: LongInt): LongInt;
  241.  
  242.         VAR
  243.             num: LongInt;
  244.             i: INTEGER;
  245.  
  246.         BEGIN
  247.             i := ArgVIndex + 1; { get index of numeric argument }
  248.             IF i >= ArgC THEN { if we've run out of parameters }
  249.                 SyntaxError(concat('The "', ArgV^[ArgVIndex]^, '" option requires a numeric parameter'));
  250.             IF ArgV^[i]^[1] = '$' THEN { if arg has a leading $ }
  251.                 HexStringToNum(ArgV^[i]^, num) { convert hex string }
  252.             ELSE
  253.                 StringToNum(ArgV^[i]^, num); { convert decimal string }
  254.             IF (num < Low) OR (num > High) THEN { check range }
  255.                 BEGIN
  256.                 WriteLn(Diagnostic, '### ', progName, ' - ', '"', ArgV^[ArgVIndex]^, '" option requires ', Low, ' <= ', Name, ' <= ', High, '.');
  257.                 SyntaxError(kNull);
  258.                 END;
  259.             ArgVIndex := i; { update argV index }
  260.             GetNumArg := num; { return the value }
  261.         END; { GetNumArg }
  262.  
  263.     {=== GetAlphaArg - Get a string argument after a letter option ===}
  264.  
  265.     FUNCTION GetAlphaArg(VAR ArgVIndex: INTEGER): Str255;
  266.  
  267.         VAR
  268.             i: INTEGER;
  269.  
  270.         BEGIN
  271.             i := ArgVIndex + 1; { get index of numeric argument }
  272.             IF i >= ArgC THEN { if we've run out of parameters }
  273.                 SyntaxError(concat('The "', ArgV^[ArgVIndex]^, '" option requires an alphanumeric parameter'));
  274.             ArgVIndex := i; { update argV index }
  275.             GetAlphaArg := ArgV^[i]^; { return the string }
  276.         END; { GetAlphaArg }
  277.  
  278.     {=== LetterOpt - Set a letter option ===}
  279.  
  280.     PROCEDURE LetterOpt(opt: Char;
  281.                                             VAR ArgVIndex: INTEGER);
  282.  
  283.     { ArgVIndex is passed to this routine so options that have arguments can 'eat' them }
  284.  
  285.         VAR
  286.             st: Str255;
  287.             i: INTEGER;
  288.  
  289.         BEGIN { LetterOpt }
  290.             CASE opt OF
  291.                 'p', 'P': progress := TRUE;
  292.                 'a', 'A': address := GetNumArg(ArgVIndex, 'address', - MAXLONGINT, MAXLONGINT);
  293.                 'h', 'H':
  294.                     BEGIN
  295.                     st := ToUpper(GetAlphaArg(ArgVIndex));
  296.                     IF st = 'RAW' THEN
  297.                         hexType := raw
  298.                     ELSE
  299.                         IF st = 'INTEL' THEN
  300.                             hexType := intel
  301.                         ELSE
  302.                             IF st = 'S1' THEN
  303.                                 hexType := motorolaS1
  304.                             ELSE
  305.                                 IF st = 'S2' THEN
  306.                                     hexType := motorolaS2
  307.                                 ELSE
  308.                                     IF st = 'S3' THEN
  309.                                         hexType := motorolaS3
  310.                                     ELSE
  311.                                         SyntaxError(concat(ArgV^[ArgVIndex]^, ' <invalid hex type>'));
  312.                     END;
  313.                 'm', 'M':
  314.                     BEGIN
  315.                     st := ToUpper(GetAlphaArg(ArgVIndex));
  316.                     IF st = 'ALL' THEN
  317.                         hexMode := allBytes
  318.                     ELSE
  319.                         IF st = 'EVEN' THEN
  320.                             hexMode := evenBytes
  321.                         ELSE
  322.                             IF st = 'ODD' THEN
  323.                                 hexMode := oddBytes
  324.                             ELSE
  325.                                 SyntaxError(concat(ArgV^[ArgVIndex]^, ' <invalid hex mode>'));
  326.                     END;
  327.                 'r', 'R':
  328.                     BEGIN
  329.                     st := GetAlphaArg(ArgVIndex);
  330.                     IF Length(st) <> 4 THEN SyntaxError(concat(ArgV^[ArgVIndex]^, ' <invalid resource type>'));
  331.                     FOR i := 1 TO 4 DO rType[i] := st[i];
  332.                     END;
  333.                 'i', 'I': rID := GetNumArg(ArgVIndex, 'resid', - MAXINT, MAXINT);
  334.                 's', 'S': skip := GetNumArg(ArgVIndex, 'skip', 0, MAXLONGINT);
  335.                 OTHERWISE SyntaxError(concat(ArgV^[ArgVIndex]^, ' <invalid option>'));
  336.             END;
  337.         END; { LetterOpt }
  338.  
  339.     {=== Init - Tool initalization ===}
  340.  
  341.     PROCEDURE Init;
  342.  
  343.         VAR
  344.             ArgVIndex, fileCount: INTEGER;
  345.             prevSig: SignalHandler;
  346.             arg: Str255;
  347.             h: Handle;
  348.  
  349.         BEGIN { Init }
  350.             retCode := RC_Normal;
  351.             interrupted := FALSE; { becomes TRUE when interrupted }
  352.             prevSig := IEsignal(SIGINT, @Intr);
  353.             progName := ArgV^[0]^;
  354.             progress := FALSE; { set up default options }
  355.             address := 0;
  356.             hexType := intel;
  357.             hexMode := allBytes;
  358.             rType := 'CODE';
  359.             rID := 1;
  360.             skip := 4;
  361.             codeH := NIL;
  362.             retCode := RC_ParmErrs;
  363.             fileCount := 0;
  364.             fileRef := - 1; { so we tell if the open works }
  365.             ArgVIndex := 1;
  366.             WHILE ArgVIndex < ArgC DO { ArgC is the number of args plus one }
  367.                 BEGIN
  368.                 arg := ArgV^[ArgVIndex]^;
  369.                 IF (Length(arg) <> 0) THEN
  370.                     BEGIN
  371.                     IF arg[1] = '-' THEN { we have an option }
  372.                         LetterOpt(arg[2], ArgVIndex)
  373.                     ELSE { it must be a file to open }
  374.                         BEGIN
  375.                         fileCount := fileCount + 1;
  376.                         fileName := arg;
  377.                         END;
  378.                     END;
  379.                 ArgVIndex := ArgVIndex + 1;
  380.                 END;
  381.             IF fileCount < 1 THEN SyntaxError('Resource file must be specified');
  382.             IF fileCount > 1 THEN SyntaxError('Too many resource files specified');
  383.             retCode := RC_FileNotFound;
  384.             SetResLoad(FALSE); { prevent preloads }
  385.             fileRef := OpenResFile(fileName); { open resource file }
  386.             SetResLoad(TRUE);
  387.             IF fileRef < 0 THEN
  388.                 Stop(concat('### ', progName, ' - could not open ', fileName))
  389.             ELSE
  390.                 BEGIN
  391.                 retCode := RC_ResNotFound;
  392.                 h := Get1Resource(rType, rID); { get the resource }
  393.                 IF h = NIL THEN
  394.                     Stop(concat('### ', progName, ' - could not load resource'))
  395.                 ELSE
  396.                     BEGIN
  397.                     DetachResource(h);
  398.                     HNoPurge(h); { make sure it doesn't get purged }
  399.                     HUnLock(h); { make sure it's relocatable until we need it }
  400.                     CloseResFile(fileRef);
  401.                     codeH := CodeHandle(h);
  402.                     END;
  403.                 END;
  404.             retCode := RC_Normal;
  405.             IF progress THEN
  406.                 BEGIN
  407.                 WriteLn(Diagnostic);
  408.                 WriteLn(Diagnostic, progName, ' (Version ', Version, ')');
  409.                 WriteLn(Diagnostic);
  410.                 WriteLn(Diagnostic, 'file name     = ', fileName);
  411.                 WriteLn(Diagnostic, 'address       = ', address: 8);
  412.                 WriteLn(Diagnostic, 'hex type      = ', Ord(hexType): 8);
  413.                 WriteLn(Diagnostic, 'hex mode      = ', Ord(hexMode));
  414.                 WriteLn(Diagnostic, 'resource type = ', rType: 8);
  415.                 WriteLn(Diagnostic, 'resource ID   = ', rID: 8);
  416.                 WriteLn(Diagnostic, 'skip          = ', skip: 8);
  417.                 WriteLn(Diagnostic);
  418.                 END;
  419.         END; { Init }
  420.  
  421.     {$S Main }
  422.  
  423.     {=== DoIt - the guts of the program ===}
  424.  
  425.     PROCEDURE DoIt;
  426.  
  427.         VAR
  428.             cursorCount: INTEGER; { for our spinning cursor }
  429.  
  430.         PROCEDURE DoHex;
  431.  
  432.             VAR
  433.                 codeP: CodePtr;
  434.                 oSt: Str255;
  435.                 b, inBytes, outBytes, maxBytes, cs, dummy: INTEGER;
  436.                 done: Boolean;
  437.                 err: OSErr;
  438.                 codeByte: Byte;
  439.                 addr, i, iMax, codeSize: LongInt;
  440.                 st1, st2: Str255;
  441.  
  442.             FUNCTION HexString(ndigits: INTEGER;
  443.                                                  i: LongInt): Str255;
  444.  
  445.                 VAR
  446.                     st: Str255;
  447.                     st1: Str1;
  448.  
  449.                 BEGIN { HexString }
  450.                     st := kNull;
  451.                     st1 := kSpace;
  452.                     WHILE ndigits > 0 DO
  453.                         BEGIN
  454.                         st1[1] := HexChar(i MOD $10); { convert least sig digit to string }
  455.                         st := concat(st1, st); { put digit on front of string }
  456.                         i := i DIV $10; { shift everything right one digit }
  457.                         ndigits := ndigits - 1; { reduce the digit count }
  458.                         END;
  459.                     HexString := st;
  460.                 END; { HexString }
  461.  
  462.             BEGIN { DoHex }
  463.                 codeSize := GetHandleSize(Handle(codeH)); { get size of code resource }
  464.                 IF progress THEN
  465.                     BEGIN
  466.                     WriteLn(Diagnostic, 'resource size = ', codeSize: 8);
  467.                     WriteLn(Diagnostic);
  468.                     END;
  469.                 CASE hexType OF
  470.                     raw, intel: ; { no preamble for raw or Intel format }
  471.                     motorolaS1, motorolaS2, motorolaS3: WriteLn('S0030000FC'); { standard preamble for Motorola formats }
  472.                 END;
  473.                 HLock(Handle(codeH)); { lock down our CODE resource }
  474.                 codeP := codeH^; { de-reference it for speed }
  475.                 iMax := codeSize - 1; { get max index }
  476.                 done := FALSE;
  477.                 addr := address;
  478.                 CASE hexMode OF
  479.                     allBytes:
  480.                         BEGIN
  481.                         i := skip; { skip first N bytes }
  482.                         maxBytes := 32;
  483.                         END;
  484.                     evenBytes:
  485.                         BEGIN
  486.                         IF Odd(skip) THEN
  487.                             i := skip + 1 { skip first N bytes + 1 }
  488.                         ELSE
  489.                             i := skip; { skip first N bytes }
  490.                         maxBytes := 64;
  491.                         END;
  492.                     oddBytes:
  493.                         BEGIN
  494.                         IF Odd(skip) THEN
  495.                             i := skip { skip first N bytes + 1 }
  496.                         ELSE
  497.                             i := skip + 1; { skip first N bytes + 1 }
  498.                         maxBytes := 64;
  499.                         END;
  500.                 END;
  501.                 REPEAT
  502.                     IF interrupted THEN Stop(kNull);
  503.                     RotateCursor(cursorCount);
  504.                     cursorCount := cursorCount + 2;
  505.                     IF (iMax - i) < maxBytes THEN
  506.                         BEGIN
  507.                         inBytes := iMax - i + 1;
  508.                         done := TRUE;
  509.                         END
  510.                     ELSE
  511.                         inBytes := maxBytes;
  512.                     CASE hexMode OF
  513.                         allBytes: outBytes := inBytes;
  514.                         evenBytes, oddBytes: outBytes := (inBytes + 1) DIV 2;
  515.                     END;
  516.                     IF outBytes > 0 THEN
  517.                         BEGIN
  518.                         CASE hexType OF
  519.                             raw: oSt := kNull;
  520.                             intel:
  521.                                 BEGIN
  522.                                 addr := addr MOD $10000; { 16 bit addresses }
  523.                                 oSt := concat(':', HexString(2, outBytes), HexString(4, addr), '00');
  524.                                 cs := outBytes + (addr DIV $100) + (addr MOD $100); { init checksum }
  525.                                 END;
  526.                             motorolaS1:
  527.                                 BEGIN
  528.                                 addr := addr MOD $10000; { 16 bit addresses }
  529.                                 oSt := concat('S1', HexString(2, outBytes + 3), HexString(4, addr));
  530.                                 cs := outBytes + 3 + (addr DIV $100) + (addr MOD $100); { init checksum }
  531.                                 END;
  532.                             motorolaS2:
  533.                                 BEGIN
  534.                                 addr := addr MOD $1000000; { 24 bit addresses }
  535.                                 oSt := concat('S2', HexString(2, outBytes + 4), HexString(6, addr));
  536.                                 cs := outBytes + 4 + (addr DIV $10000) + (addr DIV $100) + (addr MOD $100); { init checksum }
  537.                                 END;
  538.                             motorolaS3:
  539.                                 BEGIN
  540.                                 oSt := concat('S3', HexString(2, outBytes + 5), HexString(8, addr));
  541.                                 cs := outBytes + 5 + (addr DIV $1000000) + (addr DIV $10000) + (addr DIV $100) + (addr MOD $100); { init checksum }
  542.                                 END;
  543.                         END;
  544.                         FOR b := 1 TO outBytes DO
  545.                             BEGIN
  546.                             codeByte := codeP^[i]; { get next byte }
  547.                             CASE hexMode OF
  548.                                 allBytes: i := i + 1; { bump index to next byte }
  549.                                 evenBytes, oddBytes: i := i + 2;
  550.                             END;
  551.                             oSt := concat(oSt, HexString(2, codeByte)); { add to output string }
  552.                             cs := cs + codeByte; { bump checksum calculation }
  553.                             END;
  554.                         IF hexType IN [intel, motorolaS1, motorolaS2, motorolaS3] THEN { if we need a checksum }
  555.                             BEGIN
  556.                             cs := cs MOD $100; { use only least sig 8 bits for checksum }
  557.                             IF hexType = intel THEN { fix checksum according to hex type }
  558.                                 cs := $100 - cs { Intel checksum }
  559.                             ELSE
  560.                                 cs := $FF - cs; { Motorola checksum }
  561.                             oSt := concat(oSt, HexString(2, cs)); { append checksum }
  562.                             END;
  563.                         WriteLn(oSt);
  564.                         addr := addr + outBytes;
  565.                         END;
  566.                 UNTIL done;
  567.                 CASE hexType OF
  568.                     intel: WriteLn(':00000001FF');
  569.                     motorolaS1: WriteLn('S9030000FC');
  570.                     motorolaS2: WriteLn('S804000000FB');
  571.                     motorolaS3: WriteLn('S70500000000FA');
  572.                 END;
  573.                 HUnLock(Handle(codeH)); { unlock our code resource }
  574.                 DisposHandle(Handle(codeH)); { dispose of it }
  575.             END; { DoHex }
  576.  
  577.         BEGIN { DoIt }
  578.             cursorCount := 0; { prepare to spin the cursor }
  579.             DoHex;
  580.             Stop(kNull);
  581.         END; { DoIt }
  582.  
  583.     {=== Hex - main program ===}
  584.  
  585.     BEGIN
  586.         Init; { sets up world, opens our resource file }
  587.         UnLoadSeg(@Init); { release our initialization segment }
  588.         DoIt; { and call our main routine }
  589.     END.
  590.